-- GameBoardM
-- Create by cheny3
-- 游戏公告

module("GameBoardM", package.seeall);

-- 公告数据
local gameBoardData = {};
-- 玩家阅读数据
local readRecord = {};

-- 联系方式开关是否开启
local contactEnabled = 0;

-- 本地留存公告统计
local localBoardStatistics = "board/statistics.txt";
local BOARD_PATH = "board/%s.txt";
local StaticLink = "statistics.json";
local localWebBoards = {};
local UPDATE_BOARD_TYPE  = 2; -- 维护公告

-- 模块初始化
function init()
    -- 清除数据
    gameBoardData = {};
    readRecord = {};

    -- 从WEB拉取的数据
    WebInitGameBoard();

    EventMgr.removeAll("GameBoardM");
    EventMgr.register("GameBoardM", event.USER_INFO_UPDATED, function(args)
        if args == "create_time" then
            setUserFirstGameBoardTime();
        end
    end);
end

-- 游戏公告更新
function receiveGameBoards(boards)
    -- 清除原来记录
    gameBoardData = {};
    -- 整理一下获得的公告
    for index, m in pairs(boards) do
        gameBoardData[index] = m;
    end

    -- 抛出更新事件
    EventMgr.fire(event.BOARDS_UPDATE);
end

-- 获取首条游戏公告
function getFirstGameBoard()
    local content = "";
    local title = getLocStr("system_board_title");
    for i = 1, 9 do
        content = content .. getLocStr("system_board_" .. i);
    end

    -- 需要根据是否海外版本决定联系方式的内容
    if isOverseaPackage() then
        if "zh" == getLang() or "tw" == getLang() then
            content = content .. getLocStr("system_board_10");
        else
            -- 非中文语言版本使用英文空间
            content = content .. getLocStr("system_board_12");
        end
    elseif PUBLISH_PLATFORM == PUBLISH_TYPE_UC then
        -- 如果是uc平台，默认不显示联系方式，只有联系方式开关打开时才需要显示
        if isContactEnabled() then
            content = content .. getLocStr("system_board_11");
        end
    elseif PUBLISH_PLATFORM == PUBLISH_TYPE_LT then
        content = content .. getLocStr("system_board_13");
    else
        content = content .. getLocStr("system_board_11");
    end

    local showTime = UserDefaultM.getStringForKey("first_board_time");
    if showTime == nil or showTime == "" then
        -- 当前时间
        local t = os.date("*t", TimeM.getCurrentTime());

        showTime = string.format(getLocStr("system_board_date"), t.year, t.month, t.day);
        UserDefaultM.setStringForKey("first_board_time", showTime);
    end

    return {["title"] = title, ["content"] = content, ["showTime"] = showTime};
end

-- 获取第三条游戏公告（Peter）
function getThirdGameBoard()
    local content = "";
    local title = getLocStr("peter_mail_title");
    for i = 1, 19 do
        content = content .. getLocStr("peter_mail_" .. i);
    end

    local appName = getLocStr("peter_mail_game_name1");
    if not isOverseaPackage() then
        -- 国内的使用不思议迷宫
        appName = getLocStr("peter_mail_game_name2");
    end

    -- 拼名字
    content = string.gsub(content, "{app_name}", appName);

    local showTime = UserDefaultM.getStringForKey("first_board_time");
    if showTime == nil or showTime == "" then
        -- 当前时间
        local t = os.date("*t", TimeM.getCurrentTime());

        showTime = string.format(getLocStr("system_board_date"), t.year, t.month, t.day);
        UserDefaultM.setStringForKey("first_board_time", showTime);
    end

    return {["title"] = title, ["content"] = content, ["showTime"] = showTime};
end

-- 获取第二条游戏公告（研发名单）
function getSecondGameBoard()
    local content = "";
    local title = getLocStr("rdlist_title");
    for i = 1, 19 do
        content = content .. getLocStr("rdlist_" .. i);
    end
    local name = getLocStr("rdlist_name");

    return {["title"] = title, ["content"] = name, ["name"] = content};
end

-- 获取游戏公告
function getGameBoards()
    return gameBoardData;
end

-- 获取某ID游戏公告详细内容
function getGameBoardById(id)
    local board = {};
    if gameBoardData[id] then
        board = gameBoardData[id];
    end
    return board;
end

-- 获取游戏外公告
function getOutBoard()
    local outBoard = {};

    local lang = UserDefaultM.getStringForKey("APP_LANG");
    if lang == nil or lang == "" then
        -- 默认英文
        lang = "en";
    end

    if _G["outBoard"] then
        outBoard["title"] = _G["outBoard"]["boardTitle_" .. lang] or _G["outBoard"]["boardTitle_en"] or "";
        outBoard["content"] = _G["outBoard"]["boardContent_" .. lang] or _G["outBoard"]["boardContent_en"] or "";
        outBoard["showTime"] = _G["outBoard"]["boardData"] or "";
    end
    return outBoard;
end

-- 获取某Id游戏公告内容
function getGameBoardContentById(id)
    if type(id) == "string" then
        -- WEB拉取的公告
        return WebGetGameBoardById(id);
    end

    if id == 0 then
        -- 游戏外公告
        return getOutBoard();
    elseif id == -1 then
        -- 默认公告
        return getFirstGameBoard();
    elseif id == -2 then
        -- 研发名单
        return getSecondGameBoard();
    elseif id == -3 then
        -- Peter一封信
        return getThirdGameBoard();
    end

    local board = getGameBoardById(id);
    -- 根据语言版本获取内容
    local title = board["name_" .. getLang()];
    -- 如果没有则默认取英文的
    if not title then
        title = board["name_en"] or "";
    end

    local content = board["message_".. getLang()];
    -- 如果没有则默认取英文的
    if not content then
        content = board["message_en"] or "";
    end

    return {["title"] = title, ["content"] = content, ["showTime"] = board["show_time"],
        ["activity"] = board["activity"]};
end

-- 获取当前所有的标题
function getAllTitle()
    local titles = {};
    local titleInfo = {};

    -- web拉取的
    local createTime = UserDefaultM.getStringForKey("create_time");
    for _, m in pairs(localWebBoards) do
        repeat
            local distStr = m["dist"] or "*";
            if distStr ~= "*" then
                local distArr = string.explode(distStr, "|");
                local lastAAAId = UserDefaultM.getStringForKey("aaa_id");

                if lastAAAId ~= "" and table.indexOf(distArr, tostring(lastAAAId)) < 0 then
                    break;
                end
            end

            local showLanguage = m["show_language"] or "*";
            if showLanguage ~= "*" then
                local langs = string.explode(showLanguage, "|");

                -- 限制了语言
                if table.indexOf(langs, getLang()) < 0 then
                    break;
                end
            end

            -- 如果是活动公告，需要判断是否已经过期
            if type(m["activity"]) == "table" then
                local info = m["activity"];
                local openTime = info["open_time"];
                local endTime = openTime + info["last_hour"] * 3600;
                if endTime <= TimeM.getServerTime() or not ME.isInGame then
                    -- 活动已经结束了/当前没有登陆游戏不显示
                    break;
                end
            end

            -- 不是维护公告/或者维护公告发布时间大于玩家账号创建时间
            if m["type"] ~= UPDATE_BOARD_TYPE
                or m["create_time"] > tonumber(createTime) then
                -- 构造信息
                titleInfo = {
                    ["id"] = m["id"],
                    ["title"] = m["name_" .. getLang()] or m["name_en"] or "",
                    ["type"] = m["type"],
                    ["web"] = true,
                    ["force_show"] = m["force_show"],
                    ["create_time"] = m["create_time"],
                }
                -- 插入信息
                table.insert(titles, titleInfo);
            end
        until true;
    end

    -- 游戏中下发的
    for index, m in pairs(gameBoardData) do
        -- 构造信息
        titleInfo = {
            ["id"] = m["id"],
            ["title"] = m["name_" .. getLang()] or m["name_en"] or "",
            ["type"] = m["type"],
            ["force_show"] = m["force_show"],
            ["create_time"] = m["create_time"],
        }
        -- 插入信息
        table.insert(titles, titleInfo);
    end

    -- 支持动态开关的部分
    local board_close = ServerStatusM.query(MODULE_SWITCH_BOARD_CLOSE) or {};
    local m = LPC.restoreString(UserDefaultM.getStringForKey("board_close"));
    if type(m) == "table" then
        board_close = m;
    end

    if table.indexOf(board_close, 1) == -1 then
        -- 游戏默认公告1(首封)
        titleInfo = {
            ["id"] = -1,
            ["title"] = getFirstGameBoard().title,
            ["type"] = 1,
            ["force_show"] = 1,
            ["create_time"] = 0, -- 默认排在倒数第三
        }

        -- 插入信息
        table.insert(titles, titleInfo);
    end

    if table.indexOf(board_close, 2) == -1 then
        -- 游戏默认公告2(开发组)
        titleInfo = {
            ["id"] = -2,
            ["title"] = getSecondGameBoard().title,
            ["type"] = 1,
            ["create_time"] = -2, -- 默认排在倒数第一
        }

        -- 插入信息
        table.insert(titles, titleInfo);
    end

    -- 国内的版本不显示 PETER的一封信
    if table.indexOf(board_close, 3) == -1 and
       isOverseaPackage() then
        -- 游戏默认公告3(Peter)
        titleInfo = {
            ["id"] = -3,
            ["title"] = getThirdGameBoard().title,
            ["type"] = 1,
            ["force_show"] = 1,
            ["create_time"] = -1, -- 默认排在倒数第二
        }

        -- 插入信息
        table.insert(titles, titleInfo);
    end

    -- 按创建时间排序
    local function sortFunc(a, b)
        local createTimeA = a["create_time"] or 1000;
        local createTimeB = b["create_time"] or 1000;
        return createTimeA > createTimeB;
    end
    table.sort(titles, sortFunc);

    return titles;
end

-- 获取当前信息总条数
function getTitleCount()
    return #getAllTitle();
end

-- 设置玩家阅读公告记录
function setUserReadRecord(record)
    -- 替换原来记录
    readRecord = record;
end

-- 获取玩家阅读公告记录
function getUserReadRecord()
    local retRecord = table.deepcopy(readRecord);

    -- 本地默认的公告
    local systemBoard = {};
    if UserDefaultM.getStringForKey("read_system_board") == 1 then
        -- 旧数据兼容
        table.insert(systemBoard, -1);
    else
        local m = LPC.restoreString(UserDefaultM.getStringForKey("read_system_board"));
        if type(m) == "table" then
            systemBoard = m;
        end
    end

    -- 合并
    retRecord = table.append(systemBoard, retRecord);

    -- 本地留存WEB公告
    if UserDefaultM.getStringForKey("web_board_record") == nil
        or UserDefaultM.getStringForKey("web_board_record") == "" then
        UserDefaultM.setStringForKey("web_board_record", LPC.saveString({}));
    end
    local readLog = LPC.restoreString(UserDefaultM.getStringForKey("web_board_record"));
    for _, id in pairs(readLog) do
        table.insert(retRecord, id);
    end

    return retRecord;
end

-- 是否阅读过首封公告
function hasReadFirstBoard()
    local readRecord = LPC.restoreString(UserDefaultM.getStringForKey("read_system_board"));
    if type(readRecord) ~= "table" then
        -- 兼容旧数据
        if readRecord == 1 then
            readRecord = {-1};
        else
            readRecord = {};
        end

        UserDefaultM.setStringForKey("read_system_board", LPC.saveString(readRecord));
    end

    return table.indexOf(readRecord, -1) >= 0;
end

-- 增加玩家阅读公告记录
function addUserReadRecord(id)
    if type(id) == "string" then
        -- WEB拉取的不用去设置，直接在本地设置
        WebAddUserReadRecord(id);
        return;
    end

    -- 本地公告
    local m = LPC.restoreString(UserDefaultM.getStringForKey("read_system_board"));
    if type(m) ~= "table" then
        m = {};
    end

    if id < 0 then
        if table.indexOf(m, id) < 0 then
            table.insert(m, id);
            UserDefaultM.setStringForKey("read_system_board", LPC.saveString(m));
        end
        return;
    end

    if table.indexOf(readRecord, id) ~= -1 then
        return;
    end

    table.insert(readRecord, id);
    -- 通知服务器阅读过了
    Operation.cmd_update_read_boards_record(id);
end

-- 获取玩家当前还没阅读的最新公告
function getLastNotReadId()
    local maxId = 0;
    for _, m in pairs(getAllTitle()) do
        if table.indexOf(getUserReadRecord(), m["id"]) == -1
            and m["force_show"] and m["force_show"] == 1 then
            maxId = m["id"];
            break;
        end
    end

    return maxId;
end

-- 设置玩家首条公告时间
function setUserFirstGameBoardTime()
    local createTime = ME.user.dbase:query("create_time");
    if createTime then
        local t = os.date("*t", createTime - TimeM.getTimeOffsetDifference());
        local showTime = string.format(getLocStr("system_board_date"), t.year, t.month, t.day);
        UserDefaultM.setStringForKey("first_board_time", showTime);
        UserDefaultM.setStringForKey("create_time", createTime);
    end
end

---------以下为SLIMEC-2988修改增加-----------
-- 修改游戏常规公告从WEB拉取
-- 所有函数以WEB打头

-- 初始化本地留存的web公告
function WebInitGameBoard()
    localWebBoards = {};
    local ids = WebGetLocalBoardIds();
    for _, id in pairs(ids) do
        local pathName = string.format(BOARD_PATH, id);
        localWebBoards[id] = file.readFile(pathName);
    end
end

-- 获取公告内容（返回游戏中用的格式）
function WebGetGameBoardById(id)
    local board = WebGameBoardInfo(id);
    -- 根据语言版本获取内容
    local title = board["name_" .. getLang()];
    -- 如果没有则默认取英文的
    if not title then
        title = board["name_en"] or "";
    end

    local content = board["message_".. getLang()];
    -- 如果没有则默认取英文的
    if not content then
        content = board["message_en"] or "";
    end

    return {["title"] = title, ["content"] = content, ["showTime"] = board["show_time"],
        ["activity"] = board["activity"]};
end

-- 获取某个ID的公告文件
function WebGameBoardInfo(id)
    local pathName = string.format(BOARD_PATH, id);
    if not file.isFileExist(pathName) then
        return;
    end
    return file.readFile(pathName);
end

-- 检查游戏常规公告（UILogin/UIMainMap使用）
function WebcheckGameBoard()
    if type(WEB_BOARD_URL) ~= "string" then
        -- 未配置地址，不检查
        print("无效WEB_BOARD_URL"..tostring(WEB_BOARD_URL));
        return false;
    end

    -- 下载链接
    local url  = WEB_BOARD_URL .. "/" .. StaticLink;

    if url == "" then
        -- 无效的url，执行自动更新
        print("无效WEB_BOARD_URL");
        return false;
    end

    local function whenResponse(responseData)
        if not responseData then
            -- 连接不上主机，默认执行自动更新
            print("连接不上WEB_BOARD_URL所在的主机: " .. url);
            return false;
        end

        -- 替换\\n
        string.gsub(responseData, "\n", "\\n");
        -- 解析json数据
        local function decode()
            return json.decode(responseData, 1);
        end

        local status, output = xpcall(decode, function(msg) return msg; end);
        if not status then
            print("### 解析WEB_BOARD_URL数据失败了！");
            return false;
        end

        -- 分析数据
        WebGameBoardAnalysis(output);
    end

    -- 到远程主机获取数据
    getRemoteHostData(url, whenResponse);

    return true;
end

local DIR_NAME = "board";

-- 分析下发的数据
function WebGameBoardAnalysis(data)
   -- 先试图去创建一个文件夹
   if not file.isDirectoryExist("board") then
       file.createDirectory(DIR_NAME);
   end

   local newIds = {};
   for id, value in pairs(data["board_ids"]) do
       if value == 1 then
           table.insert(newIds, id);
       end
   end

   -- 后续操作
   WebCompareBoardData(newIds);
end

-- 比较下发的和本地的数据
function WebCompareBoardData(newIds)
    -- 获取本地留存的数据
    local ids = WebGetLocalBoardIds();
    local needGet = {};
    local needRemove = {};

    for _, newId in pairs(newIds) do
        if (table.indexOf(ids, newId) == -1) then
            -- 需要去拉取的
            table.insert(needGet, newId);
        end
    end

    for _, oldId in pairs(ids) do
        if (table.indexOf(newIds, oldId) == -1) then
            -- 需要删除的
            table.insert(needRemove, oldId);
        end
    end

    -- 拉取数据
    for _, newId in pairs(needGet) do
        WebGetBoard(newId);
    end

    -- 从本地删除
    for _, oldId in pairs(needRemove) do
        WebGameBoardDelete(oldId);
    end
end

-- 拉取数据
function WebGetBoard(id)
    if type(WEB_BOARD_URL) ~= "string" then
        -- 未配置地址，不拉取
        return false;
    end

    if WEB_BOARD_URL == "" then
        -- 无效的url，不拉取
        print("无效WEB_BOARD_URL");
        return false;
    end

    -- 下载链接
    local url  = WEB_BOARD_URL .. "/" .. id .. ".json";

    local function whenResponse(responseData)
        if not responseData then
            -- 连接不上数据
            print("连接不上WEB_BOARD_URL所在的主机: " .. url);
            return false;
        end

        -- 替换\\n
        string.gsub(responseData, "\n", "\\n");
        -- 解析json数据
        local function decode()
            return json.decode(responseData, 1);
        end

        local status, output = xpcall(decode, function(msg) return msg; end);
        if not status then
            print("### 解析WEB_BOARD_URL数据失败了！");
            return false;
        end

        -- 本地增加数据
        WebGameBoardAdd(output)
    end

    -- 到远程主机获取数据
    getRemoteHostData(url, whenResponse);

    return true;
end

-- 本地删除公告数据
function WebGameBoardDelete(id)
    local pathName = string.format(BOARD_PATH, id);
    if file.isFileExist(pathName) then
        file.removeFile(pathName);
    end

    -- 从本地留存里删除
    local ids = WebGetLocalBoardIds();
    local ret = {};
    for _, per_id in pairs(ids) do
        if per_id ~= id then
            table.insert(ret, per_id);
        end
    end
    local m = file.readFile(localBoardStatistics);

    if type(m) ~= "table" then
        m = {};
    end

    m["board_ids"] = ret;

    local content2 = LPC.saveString(m);
    file.writeFile(content2, localBoardStatistics);

    -- 模块留存
    localWebBoards[id] = nil;

    -- 把阅读过的记录干掉
    if UserDefaultM.getStringForKey("web_board_record") == nil
        or UserDefaultM.getStringForKey("web_board_record") == "" then
        UserDefaultM.setStringForKey("web_board_record", LPC.saveString({}));
    end
    local readLog = LPC.restoreString(UserDefaultM.getStringForKey("web_board_record"));
    local index = table.indexOf(readLog, id);
    if index ~= -1 then
        table.remove(readLog, index);
        UserDefaultM.setStringForKey("web_board_record", LPC.saveString(readLog));
    end
end

-- 本地增加公告数据
function WebGameBoardAdd(content)
    local id = content["id"];
    local pathName = string.format(BOARD_PATH, id);
    local content1 = LPC.saveString(content);
    file.writeFile(content1, pathName);

    -- 记录到本地留存统计里
    local ids = WebGetLocalBoardIds();
    if (table.indexOf(ids, id) == -1) then
        table.insert(ids, id);
    end
    local m = {};
    if file.isFileExist(localBoardStatistics) then
        m = file.readFile(localBoardStatistics);
    end

    if type(m) ~= "table" then
        m = {};
    end

    m["board_ids"] = ids;
    local content2 = LPC.saveString(m);
    file.writeFile(content2, localBoardStatistics);

    -- 模块留存
    localWebBoards[id] = content;
end

-- 获取本地留存的所有公告ID
function WebGetLocalBoardIds()
    -- 读取本地的数据文件
    local m;
    local ids = {};
    if file.isFileExist(localBoardStatistics) then
        m = file.readFile(localBoardStatistics);
        if m["board_ids"] then
            ids = m["board_ids"];
        end
    end
    return ids;
end

-- 本地增加玩家阅读过的记录TODO
function WebAddUserReadRecord(id)
    -- 本地留存WEB公告
    if UserDefaultM.getStringForKey("web_board_record") == nil
        or UserDefaultM.getStringForKey("web_board_record") == "" then
        UserDefaultM.setStringForKey("web_board_record", LPC.saveString({}));
    end
    local readLog = LPC.restoreString(UserDefaultM.getStringForKey("web_board_record"));
    if table.indexOf(readLog, id) == -1 then
        -- 加进去
        table.insert(readLog, id);
    end
    UserDefaultM.setStringForKey("web_board_record", LPC.saveString(readLog));
end

-- 设置联系方式开关
function setContactEnabled(isEnabled)
    contactEnabled = isEnabled;
end

-- 联系方式开关是否开启
function isContactEnabled()
    return contactEnabled == 1;
end
